package cn.vehicle.biz.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.vehicle.biz.SysRoleBiz;
import cn.vehicle.domains.bo.QueryPermissionBo;
import cn.vehicle.domains.bo.QueryRoleBo;
import cn.vehicle.domains.entity.SysPermissionEntity;
import cn.vehicle.domains.entity.SysRoleEntity;
import cn.vehicle.domains.entity.SysRolePermissionEntity;
import cn.vehicle.domains.vo.BasePage;
import cn.vehicle.domains.vo.req.sysRole.AddRolePermissionReq;
import cn.vehicle.domains.vo.req.sysRole.AddRoleReq;
import cn.vehicle.domains.vo.req.sysRole.RoleListReq;
import cn.vehicle.domains.vo.req.sysRole.UpdateRoleReq;
import cn.vehicle.domains.vo.res.sysRole.SysRoleRes;
import cn.vehicle.enums.ActiveEnum;
import cn.vehicle.exception.VehicleAccessException;
import cn.vehicle.service.SysPermissionService;
import cn.vehicle.service.SysRolePermissionService;
import cn.vehicle.service.SysRoleService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 系统角色业务实现类
 * <p>
 * 负责角色的新增、修改、删除、查询与分页列表，以及角色与权限的关联维护（授权/撤权）。
 * 仅做参数校验、实体装配与分页封装，持久化与复杂校验下沉至 {@link SysRoleService} / {@link SysRolePermissionService} / {@link SysPermissionService}。
 * </p>
 *
 * <p>设计约定：</p>
 * <ul>
 *   <li>所有写操作统一通过 Service 层完成；</li>
 *   <li>变更前统一进行存在性校验，异常使用 {@link VehicleAccessException} 抛出；</li>
 *   <li>分页查询基于 PageHelper，仅拦截本线程下一条查询；</li>
 *   <li>授权时需保证角色存在、权限ID有效且为启用状态。</li>
 * </ul>
 */
@Service
public class SysRoleBizImpl implements SysRoleBiz {

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysPermissionService sysPermissionService;

    @Resource
    private SysRolePermissionService sysRolePermissionService;

    /**
     * 新增角色
     *
     * @param req 新增角色请求参数
     *            方法内完成请求到实体的属性拷贝，实际入库交由 {@link SysRoleService#addRole(SysRoleEntity)} 执行。
     */
    @Override
    public void addRole(AddRoleReq req) {
        // 装配领域实体：避免直接在 Service 层处理 VO
        SysRoleEntity sysRoleEntity = new SysRoleEntity();
        // 请求参数 → 实体对象的属性拷贝（字段名/类型需兼容）
        BeanUtils.copyProperties(req, sysRoleEntity);
        // 调用 Service 层执行新增
        sysRoleService.addRole(sysRoleEntity);
    }

    /**
     * 更新角色
     *
     * <p>会先进行存在性校验，再进行字段拷贝与更新。</p>
     *
     * @param req 更新角色请求参数，需包含主键ID
     * @throws VehicleAccessException 角色不存在时抛出
     */
    @Override
    public void updateRole(UpdateRoleReq req) {
        // 存在性校验：角色必须存在
        checkRoleExist(req.getId());

        // 仅拷贝需要更新的字段到新实体，避免误改
        SysRoleEntity updateEntity = new SysRoleEntity();
        BeanUtils.copyProperties(req, updateEntity);
        // 调用 Service 层执行更新
        sysRoleService.updateRole(updateEntity);
    }

    /**
     * 删除角色
     *
     * @param id 角色主键ID
     * @throws VehicleAccessException 角色不存在时抛出
     */
    @Override
    public void deleteRole(Long id) {
        // 删除前检查角色是否存在（可在此扩展：是否已关联用户/权限等约束）
        checkRoleExist(id);

        sysRoleService.deleteRole(id);
    }

    /**
     * 根据ID查询角色详情
     *
     * @param id 角色主键ID
     * @return 角色详情响应对象
     * @throws VehicleAccessException 角色不存在时抛出
     */
    @Override
    public SysRoleRes getRoleById(Long id) {
        // 查询并校验存在性
        SysRoleEntity sysRoleEntity = checkRoleExist(id);

        SysRoleRes sysRoleRes = new SysRoleRes();
        // 实体 → 响应对象属性拷贝
        BeanUtils.copyProperties(sysRoleEntity, sysRoleRes);
        return sysRoleRes;
    }

    /**
     * 分页查询角色列表
     *
     * <p>基于 PageHelper 实现，仅拦截本线程的下一次查询。</p>
     *
     * @param req 查询条件与分页参数
     * @return 分页结果封装（总页数、总条数、当前页数据）
     */
    @Override
    public BasePage<SysRoleRes> list(RoleListReq req) {
        // 启动分页拦截
        Page<SysRoleEntity> page = PageHelper.startPage(req.getPageNo(), req.getPageSize());


        // 组装查询 BO，避免直接把请求对象透传到 Service 层
        QueryRoleBo queryRoleBo = new QueryRoleBo();
        // 拷贝筛选条件（pageNo/pageSize 无需下传）
        BeanUtils.copyProperties(req, queryRoleBo);


        // 执行查询
        List<SysRoleEntity> sysRoleEntityList = sysRoleService.selectRoleList(queryRoleBo);
        List<SysRoleRes> list = sysRoleEntityList.stream().map(sysRoleEntity -> {
            SysRoleRes sysRoleRes = new SysRoleRes();
            // DO: 实体到响应对象的属性拷贝（字段名/类型需保持兼容）
            BeanUtils.copyProperties(sysRoleEntity, sysRoleRes);
            return sysRoleRes;
        }).toList();
        // 封装分页结果
        return BasePage.generateResult(page.getPages(), page.getTotal(), list);
    }

    /**
     * 角色授权：为指定角色批量设置权限（覆盖式）
     *
     * <p>处理逻辑：</p>
     * <ol>
     *   <li>校验角色存在；</li>
     *   <li>若权限ID列表为空，则清空该角色所有权限并返回；</li>
     *   <li>校验权限ID合法且处于启用状态；</li>
     *   <li>构造角色-权限关系列表并提交给 Service 层落库（先删后增/覆盖式）。</li>
     * </ol>
     *
     * @param req 授权请求（roleId、permissionIds）
     * @throws VehicleAccessException 角色不存在或权限非法时抛出
     */
    @Override
    public void addRolePermissions(AddRolePermissionReq req) {
        // 1) 判断角色是否存在
        checkRoleExist(req.getRoleId());

        // 2) 权限列表为空：清空角色权限并返回
        if (CollectionUtil.isEmpty(req.getPermissionIds())) {
            sysRolePermissionService.addRolePermissions(req.getRoleId() , null);
            return;
        }

        // 3) 校验权限是否合法且处于启用状态（ACTIVE）
        QueryPermissionBo queryPermissionBo = new QueryPermissionBo();
        queryPermissionBo.setIds(req.getPermissionIds());
        queryPermissionBo.setStatusList(Collections.singletonList(ActiveEnum.ACTIVE.name()));
        List<SysPermissionEntity> selectPermissionList = sysPermissionService.selectPermissionList(queryPermissionBo);
        if (CollectionUtil.isEmpty(selectPermissionList)
                || req.getPermissionIds().size() != selectPermissionList.size()) {
            throw VehicleAccessException.DATE_NOT_EXIST.newInstance("有权限id不存在");
        }

        // 4) 覆盖式写入：删除旧的，写入新的权限集合

        List<SysRolePermissionEntity> list = new ArrayList<>();
        for (Long permissionId : req.getPermissionIds()) {
            SysRolePermissionEntity sysRolePermissionEntity = new SysRolePermissionEntity();
            sysRolePermissionEntity.setRoleId(req.getRoleId());
            sysRolePermissionEntity.setPermissionId(permissionId);
            list.add(sysRolePermissionEntity);
        }
        // 提交 Service 执行覆盖式授权
        sysRolePermissionService.addRolePermissions(req.getRoleId() , list);
    }

    /**
     * 校验角色是否存在
     *
     * @param id 角色主键ID
     * @return 已存在的角色实体
     * @throws VehicleAccessException 不存在时抛出 DATE_NOT_EXIST
     */
    private SysRoleEntity checkRoleExist(Long id) {
        SysRoleEntity sysRoleEntity = sysRoleService.getRoleById(id);

        // 不存在则抛出业务异常
        if (sysRoleEntity == null) {
            throw VehicleAccessException.DATE_NOT_EXIST.newInstance("角色不存在");
        }

        return sysRoleEntity;

    }
}
